package com.genwangsun.nettydemo.websocket;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * @author GenWangSun
 * 启动一个netty server
 */
@Component
@Slf4j
public class NettyServer {

    @Autowired
    private NettyServerInitializer nettyServerInitializer;


    @Value("${websocket.port}")
    private Integer port;
    @Value("${websocket.bossThread}")
    private Integer bossThread;
    @Value("${websocket.workThread}")
    private Integer workThread;
    @Value("${websocket.TimeOut}")
    private Integer timeOut;
    @Value("${websocket.soBacklog}")
    private Integer soBacklog;


    public void run() {
        /*
          boss: 数据连接通道,负责处理连接
          work: 通信处理线程,即数据到达server后会有N个线程接受并进行业务处理
         */
        NioEventLoopGroup bossServer = new NioEventLoopGroup(bossThread);
        NioEventLoopGroup workServer = new NioEventLoopGroup(workThread);

        try {
            /*
              Netty server的启动器: BootStrap, netty启动器的配置
              报文方式，详情见 https://blog.csdn.net/yangguosb/article/details/79185799
             */
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossServer, workServer)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, soBacklog)
                    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, timeOut)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childOption(ChannelOption.TCP_NODELAY, true)
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    .childHandler(nettyServerInitializer);

            ChannelFuture register = bootstrap.bind(port).sync();
            log.info("netty server start...port is {}", port);

            register.channel().closeFuture().sync();
        } catch (Exception e) {
            log.error("netty server error: ", e);
        } finally {
            /*
              需要手动关闭并释放资源
             */
            bossServer.shutdownGracefully();
            workServer.shutdownGracefully();
        }

    }
}
